/**
 * @Package: com.rx.core.util 
 * @author: Administrator   
 * @date: 2018年1月22日 下午1:01:23
 */
package com.rx.core.util;

import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter;
import com.google.gson.internal.LazilyParsedNumber;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import com.rx.core.base.RxBaseConstant;
import com.rx.core.enm.RX_ERROR;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @className: GsonUtils 
 * @author: Administrator
 * @Description: TODO
 * @date: 2018年1月22日 下午1:01:23
 */
public class GsonUtils {
	// 日志
	public static final Logger logger = LoggerFactory.getLogger(GsonUtils.class);
	
	public static final GsonBuilder GSONBUILDER;
	
	private GsonUtils(){
		
	}
	
	public static final TypeAdapter<String> STRING = new TypeAdapter<String>(){
		@Override
		public String read(JsonReader reader){
			try {
				if(reader.peek() == JsonToken.NULL){
					reader.nextNull();
					return "";
				}
				return reader.nextString();
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}
			return "";			
		}

		@Override
		public void write(JsonWriter writer, String value) throws IOException {
			try {
				if(null == value){
					writer.nullValue();
					return ;
				}
				writer.value(value);
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}			
		}
	};
	
	public static final TypeAdapter<Number> NUMBER = new TypeAdapter<Number>(){
		@Override
		public Number read(JsonReader reader) throws IOException{
			JsonToken jsonToken = reader.peek();
			switch(jsonToken){
			case NULL:
				reader.nextNull();
				return null;
			case NUMBER:
				return new LazilyParsedNumber(reader.nextString());
			default:
				throw new JsonSyntaxException("Expecting:" +jsonToken);
			}		
		}

		@Override
		public void write(JsonWriter writer, Number value) throws IOException {
			try {
				if(null == value){
					writer.nullValue();
					return ;
				}
				writer.value(String.valueOf(value));
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}			
		}
	};	
	public static final TypeAdapter<BigDecimal> BIGDECIMAL = new TypeAdapter<BigDecimal>(){
		@Override
		public BigDecimal read(JsonReader reader) throws IOException{
			if(reader.peek() == JsonToken.NULL){
				reader.nextNull();
				return null;
			}		
			
			try{
				String stringValue = reader.nextString();
				if(EmptyChecker.isEmpty(stringValue)){
					return null;
				}
				
				return new BigDecimal(stringValue);				
			}catch(Exception e){
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
				throw new JsonSyntaxException(e);
			}

		}

		@Override
		public void write(JsonWriter writer, BigDecimal value) throws IOException {
			try {
				if(null == value){
					writer.nullValue();
					return ;
				}
				writer.value(String.valueOf(value));
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}			
		}
	};	
	
	public static final TypeAdapter<Number> SHORT = new TypeAdapter<Number>(){
		@Override
		public Number read(JsonReader reader) throws IOException{
			if(reader.peek() == JsonToken.NULL){
				reader.nextNull();
				return null;
			}		
			
			try{
				String stringValue = reader.nextString();
				if(EmptyChecker.isEmpty(stringValue)){
					return null;
				}
				
				return Short.parseShort(stringValue);				
			}catch(Exception e){
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
				throw new JsonSyntaxException(e);
			}		
		}

		@Override
		public void write(JsonWriter writer, Number value) throws IOException {
			try {
				if(null == value){
					writer.nullValue();
					return ;
				}
				writer.value(String.valueOf(value));
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}			
		}
	};	
	
	public static final TypeAdapter<Number> INTEGER = new TypeAdapter<Number>(){
		@Override
		public Number read(JsonReader reader) throws IOException{
			if(reader.peek() == JsonToken.NULL){
				reader.nextNull();
				return null;
			}		
			
			try{
				String stringValue = reader.nextString();
				if(EmptyChecker.isEmpty(stringValue)){
					return null;
				}
				
				return Integer.parseInt(stringValue);				
			}catch(Exception e){
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
				throw new JsonSyntaxException(e);
			}		
		}

		@Override
		public void write(JsonWriter writer, Number value) throws IOException {
			try {
				if(null == value){
					writer.nullValue();
					return ;
				}
				writer.value(String.valueOf(value));
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}			
		}
	};
	
	public static final TypeAdapter<Number> LONG = new TypeAdapter<Number>(){
		@Override
		public Number read(JsonReader reader) throws IOException{
			if(reader.peek() == JsonToken.NULL){
				reader.nextNull();
				return null;
			}		
			
			try{
				String stringValue = reader.nextString();
				if(EmptyChecker.isEmpty(stringValue)){
					return null;
				}
				
				return Long.parseLong(stringValue);				
			}catch(Exception e){
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
				throw new JsonSyntaxException(e);
			}		
		}

		@Override
		public void write(JsonWriter writer, Number value) throws IOException {
			try {
				if(null == value){
					writer.nullValue();
					return ;
				}
				writer.value(String.valueOf(value));
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}			
		}
	};
	
	public static final TypeAdapter<Number> FLOAT = new TypeAdapter<Number>(){
		@Override
		public Number read(JsonReader reader) throws IOException{
			if(reader.peek() == JsonToken.NULL){
				reader.nextNull();
				return null;
			}		
			
			try{
				String stringValue = reader.nextString();
				if(EmptyChecker.isEmpty(stringValue)){
					return null;
				}
				
				return Float.parseFloat(stringValue);				
			}catch(Exception e){
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
				throw new JsonSyntaxException(e);
			}		
		}

		@Override
		public void write(JsonWriter writer, Number value) throws IOException {
			try {
				if(null == value){
					writer.nullValue();
					return ;
				}
				writer.value(String.valueOf(value));
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}			
		}
	};
	
	public static final TypeAdapter<Number> DOUBLE = new TypeAdapter<Number>(){
		@Override
		public Number read(JsonReader reader) throws IOException{
			if(reader.peek() == JsonToken.NULL){
				reader.nextNull();
				return null;
			}		
			
			try{
				String stringValue = reader.nextString();
				if(EmptyChecker.isEmpty(stringValue)){
					return null;
				}
				
				return Double.parseDouble(stringValue);				
			}catch(Exception e){
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
				throw new JsonSyntaxException(e);
			}		
		}

		@Override
		public void write(JsonWriter writer, Number value) throws IOException {
			try {
				if(null == value){
					writer.nullValue();
					return ;
				}
				writer.value(String.valueOf(value));
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}			
		}
	};
	
	public static final TypeAdapter<Boolean> BOOLEAN = new TypeAdapter<Boolean>(){
		@Override
		public Boolean read(JsonReader reader) throws IOException{
			if(reader.peek() == JsonToken.NULL){
				reader.nextNull();
				return null;
			}else if(reader.peek() == JsonToken.STRING){
				String stringValue = reader.nextString();
				if(EmptyChecker.isEmpty(stringValue)){
					return null;
				}
				if("0".equals(stringValue)){
					return false;
				}
				if("1".equals(stringValue)){
					return true;
				}
				return Boolean.parseBoolean(stringValue);
			}
			
			return 	reader.nextBoolean();
		}

		@Override
		public void write(JsonWriter writer, Boolean value) throws IOException {
			try {
				if(null == value){
					writer.nullValue();
					return ;
				}
				if(value){
					writer.value("1");
				}
				writer.value("0");
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}			
		}
	};
	public static final TypeAdapter<LocalDateTime> LOCAL_DATE = new TypeAdapter<LocalDateTime>(){
		@Override
		public LocalDateTime read(JsonReader reader) throws IOException{
			if(reader.peek() == JsonToken.NULL){
				reader.nextNull();
				return null;
			}else if(reader.peek() == JsonToken.STRING){
				String stringValue = reader.nextString();
				if(EmptyChecker.isEmpty(stringValue)){
					return null;
				}
				DateTimeFormatter formatter;
				if(stringValue.length()==RxBaseConstant.DATE_FORMAT_DATEONLY.length()) {
					formatter = DateTimeFormatter.ofPattern(RxBaseConstant.DATE_FORMAT_DATEONLY);
				}else if(stringValue.length()== RxBaseConstant.DATE_FORMAT_DATETIME.length()) {
					formatter = DateTimeFormatter.ofPattern(RxBaseConstant.DATE_FORMAT_DATETIME);
				}else {
					return null;
				}
				LocalDateTime dateTime = LocalDateTime.parse(stringValue, formatter);
				return 	dateTime;
			}
			return null;		
		}

		@Override
		public void write(JsonWriter writer, LocalDateTime value) throws IOException {
			try {
				if(null == value){
					writer.nullValue();
					return ;
				}
				DateTimeFormatter formatter = DateTimeFormatter.ofPattern(RxBaseConstant.DATE_FORMAT_DATETIME);
				String formattedDateTime = value.format(formatter);			
				writer.value(formattedDateTime);
			} catch (IOException e) {
				logger.error(RX_ERROR.NORMAL_ERROR.message()+e);
			}			
		}
	};	
	static{
		GSONBUILDER = new GsonBuilder();
		GSONBUILDER.registerTypeAdapter(String.class, STRING);
		GSONBUILDER.registerTypeAdapter(BigDecimal.class, BIGDECIMAL);
		GSONBUILDER.registerTypeAdapter(Number.class, NUMBER);
		GSONBUILDER.registerTypeAdapter(Short.class, SHORT);
		GSONBUILDER.registerTypeAdapter(Integer.class, INTEGER);
		GSONBUILDER.registerTypeAdapter(Long.class, LONG);
		GSONBUILDER.registerTypeAdapter(Float.class, FLOAT);
		GSONBUILDER.registerTypeAdapter(Double.class, DOUBLE);
		GSONBUILDER.registerTypeAdapter(Boolean.class, BOOLEAN);
		GSONBUILDER.registerTypeAdapter(LocalDateTime.class, LOCAL_DATE);
	}
}
